from fastapi import APIRouter, UploadFile, File, HTTPException
from ..db import session_scope, TextDoc
from ..redis_client import get_redis
import io
import json

# 尝试导入 docx2txt，用于更完整的 docx 文本抽取（包含表格等）
try:
    import docx2txt  # type: ignore
except Exception:  # pragma: no cover - 依赖缺失时回退到 python-docx
    docx2txt = None  # type: ignore


def extract_docx_text(file_bytes: bytes) -> str:
    """
    优先使用 docx2txt 抽取（更完整，能处理表格/文本框），
    失败或未安装时回退到 python-docx（段落 + 简单表格拼接）。
    """
    # 1) docx2txt 路径
    if docx2txt is not None:
        try:
            # docx2txt.process 支持路径，内存字节需写入 BytesIO 后传临时路径；
            # 但它也支持传目录输出图片，本处无需。使用临时文件更稳妥。
            with io.BytesIO(file_bytes) as bio:
                # 将内存内容写入 NamedTemporaryFile 再处理，避免部分实现对内存流不兼容
                import tempfile, os

                with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tf:
                    tf.write(bio.getvalue())
                    temp_path = tf.name
                try:
                    text = docx2txt.process(temp_path) or ""
                finally:
                    try:
                        os.unlink(temp_path)
                    except Exception:
                        pass
            if text.strip():
                return text
        except Exception:
            # 忽略并走回退
            pass

    # 2) 回退：python-docx 段落 + 表格内容
    try:
        # 延迟导入，避免在未安装时报错
        from docx import Document  # type: ignore
        doc = Document(io.BytesIO(file_bytes))
        parts: list[str] = []
        # 段落
        for p in doc.paragraphs:
            parts.append(p.text)
        # 表格（含嵌套表格）
        def table_text(tables) -> list[str]:
            acc: list[str] = []
            for t in tables:
                for row in t.rows:
                    row_cells = []
                    for cell in row.cells:
                        # 单元格内段落
                        if cell.paragraphs:
                            row_cells.append("\n".join(p.text for p in cell.paragraphs))
                        # 递归子表格
                        if cell.tables:
                            acc.extend(table_text(cell.tables))
                    if row_cells:
                        acc.append("\t".join(row_cells))
            return acc

        if doc.tables:
            parts.extend(table_text(doc.tables))

        text = "\n".join([s for s in parts if s is not None])
        return text
    except Exception:
        return ""

router = APIRouter(prefix="/texts", tags=["texts"])

@router.post("/upload")
async def upload_text(file: UploadFile = File(...)):
    filename = (file.filename or "").lower()
    content = ""
    # 统一读取字节，避免多次读取流导致丢数据
    data = await file.read()
    if filename.endswith(".txt"):
        content = data.decode("utf-8", errors="ignore")
    elif filename.endswith(".docx"):
        content = extract_docx_text(data)
    else:
        raise HTTPException(status_code=400, detail="Unsupported file format")

    with session_scope() as s:
        doc = TextDoc(content=content)
        s.add(doc)
        s.flush()
        return {"code": 0, "message": "ok", "data": {"id": str(doc.id), "content": doc.content}}

@router.get("/{doc_id}")
def get_text(doc_id: str):
    with session_scope() as s:
        item = s.get(TextDoc, doc_id)
        if not item:
            raise HTTPException(status_code=404, detail="Doc not found")
        return {"code": 0, "message": "ok", "data": {"id": str(item.id), "content": item.content}}


@router.post("/{doc_id}/autosave")
async def autosave(doc_id: str, payload: dict):
    r = get_redis()
    r.set(f"autosave:{doc_id}:anon", json.dumps(payload, ensure_ascii=False))
    return {"code": 0, "message": "ok"}


@router.get("/{doc_id}/autosave")
def get_autosave(doc_id: str):
    r = get_redis()
    val = r.get(f"autosave:{doc_id}:anon")
    return {"code": 0, "message": "ok", "data": json.loads(val) if val else None}


@router.post("/{doc_id}/progress")
async def set_progress(doc_id: str, payload: dict):
    r = get_redis()
    r.set(f"progress:{doc_id}:anon", json.dumps(payload, ensure_ascii=False))
    return {"code": 0, "message": "ok"}


@router.get("/{doc_id}/progress")
def get_progress(doc_id: str):
    r = get_redis()
    val = r.get(f"progress:{doc_id}:anon")
    return {"code": 0, "message": "ok", "data": json.loads(val) if val else None}
